/*
 ********************************************************************************
 *                      桂林聚联科技有限公司
 *                           Copyright
 *  文件描述 ： 
 *
 *
 *  文件名称 ： OtdrEventTools.c
 *  创建者   ： 
 *  创建日期 ： 2017-04-18 10:21:05
 *  当前版本 ： 
 ********************************************************************************
*/
#include <stdio.h>
#include <assert.h>
#include <math.h>

#define _DEVICE_INDEPENDENT_
#include "otdrtestinterface.h"

/*
 ********************************************************************************
 *  函数名称 ： PrintEventList
 *  函数描述 ： 打印事件点信息
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-06-08 11:04:36
 ********************************************************************************
*/
void PrintEventList(const OtdrTestResult_t *result)
{
    int i;

    if(result != NULL){
        printf("******** EVENT LIST ********\n");
        printf("Event  Position  InsertLoss  ReturnLoss  AttenCoef  TotalLoss\n");
        for(i = 0; i < result->EventNum; i++)
        {
            printf(" %-4d  %-8d  %-10.3f  %-11.3f  %-9.4f  %-9.3f\n", i, result->ep[i].EventStart, 
                    result->ep[i].EventInsertloss, result->ep[i].EventReturnloss, 
                    result->fs[i].FiberSectionAttenCoef, result->ep[i].EventTotalloss);
        }
        //printf("FiberLength = %.2fm, FiberLoss = %.3fdB, FiberAttenCoef = %.3fdB/km\n", result->FiberLen, result->FiberLoss, result->FiberAttenCoef);
    }
}

void PrintFiberList(const OtdrTestResult_t *result)
{
    float mpp;
    int i;

    if(result != NULL){
        mpp = getDataSpace(result);
        printf("******** FIBER LIST ********\n");
        printf("Fiber  FiberLen  FiberLoss  FiberAttenCoef\n");
        for(i = 0; i < result->FiberNum; i++)
        {
            printf(" %-4d  %-10.3f  %-11.3f  %-9.4f\n", i, result->fs[i].FiberSectionLen*mpp, 
                    result->fs[i].FiberSectionLoss, result->fs[i].FiberSectionAttenCoef);
        }
        printf("FiberLength = %.2fm, FiberLoss = %.3fdB, FiberAttenCoef = %.3fdB/km\n", result->FiberLen, result->FiberLoss, result->FiberAttenCoef);
    }
}

/*
 ********************************************************************************
 *  函数名称 ： GetLaserParam   GetMinAttenCoef
 *  函数描述 ： get laser parameter, attencoef and backscattercoeff
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2016-10-25 17:24:34
 ********************************************************************************
*/
void GetLaserParam(int Lambda_nm, float *AttenCoef, float *BackScatterCoeff)
{
    float k0, bsc;
    
    if(1550 == Lambda_nm)	    {   k0  = 0.185;    bsc = -82.0; }
	else if(1310 == Lambda_nm)	{   k0  = 0.321;	bsc = -80.0; }
	else if(1625 == Lambda_nm)	{   k0  = 0.2  ;	bsc = -83.0; }
    else if(1650 == Lambda_nm)	{   k0  = 0.22 ;	bsc = -84.0; }
	else if(850  == Lambda_nm)	{   k0  = 2.16 ;	bsc = -62.0; }
	else if(1300 == Lambda_nm)	{   k0  = 0.465;	bsc = -70.0; }
	else if(1490 == Lambda_nm)	{   k0  = 0.22 ;	bsc = -81.0; }
	else	                    {   k0  = 0.25 ;	bsc = -73.0; }
	
    if(NULL != AttenCoef)           *AttenCoef = k0;
    if(NULL != BackScatterCoeff)    *BackScatterCoeff = bsc;
}

float GetMinAttenCoef(int Lambda_nm)
{
    float k0;
    
    if(1550 == Lambda_nm)	    k0 = 0.17;
	else if(1310 == Lambda_nm)	k0 = 0.3;
	else if(1625 == Lambda_nm)	k0 = 0.17;
	else if(1650 == Lambda_nm)	k0 = 0.18;
	else if(850 == Lambda_nm)	k0 = 1.8;
	else if(1300 == Lambda_nm)	k0 = 0.4;
	else if(1490 == Lambda_nm)	k0 = 0.2;
	else	                    k0 = 0.25;
	
	return k0;
}

/*
 **************************************************************************************************
 *  函数  名： CalculateFiberSectionAttenCoef
 *  函数描述： 按照事件点序号计算其后的光纤段的衰减系数
 *  入口参数： Ai         : 浮点曲线数据
 *             EventTemp  : 事件点信息
 *             Ei         : 事件点序号
 *  返回参数： Ac         : 该事件点之后的光纤段的平均衰减系数
 *             b          : 该光纤段反向延长到0处的初始高度
 *  日期版本： 2013-01-10  16:45:44  v1.0
 **************************************************************************************************
*/
float CalculateFiberSectionAttenCoef(const OtdrTestParam_t *tp, const float Ai[], \
            int FinalEvent[], int FinalEventEnd[], int EventNum, int Ei, float *b)
{
	int	m, MinEventDis;
	float	ppm, atten_coeff, Ac, bt = RSVD_FLOAT;

    m = (int)(tp->PulseWidth_ns * (tp->SampleRate_Hz / 1000) / 1e6);
    ppm = 2*tp->n * tp->SampleRate_Hz / LIGHT_SPEED;
/**************************** 计算各个光纤段的衰减系数 *********************************/
    MinEventDis = (int)(ppm * 5);   // 5米对应的点数，作为两个事件点的最小距离
    MinEventDis = MIN(MinEventDis, 4*m);                // 2011-12-28 9:54:04
    
    // 根据相邻事件点的距离来判断哪些事件可以计算衰减系数
	if(0 == Ei)
	{
	    if(EventNum > 1)    // 判断下一个事件点是否与它相邻
	    {
    		if((FinalEventEnd[0] + 2*m + MinEventDis) <= FinalEvent[1])    // 如果距离足够远，则可以计算衰减系数
    		{
    		    LeastSquareMethod(Ai, FinalEventEnd[0]+m, FinalEvent[1]-m, &atten_coeff, &bt);    // 最小二乘法   2011-8-25 16:38:03
                Ac = -atten_coeff;
    		}
    		else
    		{
    		    Ac = RSVD_FLOAT;
    		}
		}
		else
		{
    		Ac = RSVD_FLOAT;
    	}
	}
	else if(EventNum-1 == Ei)
	{
	    Ac = RSVD_FLOAT;
	}
	else
	{
		if((FinalEventEnd[Ei] + 2*m + MinEventDis) <= FinalEvent[Ei+1])
		{
			LeastSquareMethod(Ai, FinalEventEnd[Ei]+m, FinalEvent[Ei+1]-m, &atten_coeff, &bt);    // 最小二乘法   2011-8-25 16:38:03
            Ac = -atten_coeff;
    	}
		else    Ac = RSVD_FLOAT;
	}
	
	if(NULL != b)   *b = bt;
	return Ac;
}

/*
 **************************************************************************************************
 *  函数  名： CalculateEventPoint_IL_RL
 *  函数描述： 根据事件组来计算光纤段的插入损耗和反射损耗
 *  入口参数： Ai        : 浮点曲线数据
 *             EventTemp : 事件点信息
 *             AC        : 光纤段的衰减系数
 *             b         : 光纤段反向延长到0处的初始高度
 *             EGS       : 事件组的起始事件序号及事件组的个数
 *             Gi        : 事件组序号
 *             bsc       : 后向散射系数
 *  返回参数： IL        : 插入损耗
 *             RL        : 反射损耗
 *             insert_loss : 该事件组的插入损耗
 *  日期版本： 2013-01-11  10:59:30  v1.0
 **************************************************************************************************
*/
float CalculateEventPoint_IL_RL(const float Ai[], int FinalEvent[], int FinalEventEnd[], const float AC[], const float b[], \
                                const EventGroupStart_t *EGS, int Gi, float bsc, float IL[], float RL[])
{
	int	i, gs1, gs2, ge0, ge1;
	const int	*EventGroupStart;
	float	Lv, Rv, Am, A0, insert_loss;
	
    EventGroupStart = EGS->EventGroupStart;         // 事件组起点

    if(0 == Gi)     /******* 起始事件组，只计算反射损耗 *******/
    {
        if(EGS->EventGroupNum > 1)
        {
		    ge1 = EventGroupStart[1]-1;
    	    fMaxValue(Ai, FinalEvent[ge1], FinalEventEnd[ge1], &Am, &i);
    	    A0 = b[ge1] - AC[ge1] * i;   // 用直线拟合出来的事件左值
    		RL[ge1] = -(bsc + 2*(Am - A0));    // 反射损耗赋予事件组里的最后一个事件
		}
		insert_loss = RSVD_FLOAT;   // 没有插损
    }
    else if(EGS->EventGroupNum-1 == Gi)    /******* 结束事件组，只计算反射损耗 *******/
    {
    	gs1 = EventGroupStart[Gi];
    	ge0 = gs1-1;
		fMaxValue(Ai, FinalEvent[gs1], FinalEventEnd[gs1], &Am, &i);
        A0 = b[ge0] - AC[ge0] * i;   // 用直线拟合出来的事件左值
		RL[gs1] = -(bsc + 2*(Am - A0));        // 反射损耗赋予事件组里的第一个事件
		insert_loss = RSVD_FLOAT;   // 没有插损
    }
    else            /******* 中间事件点，计算插入损耗、反射损耗 *******/
   	{
        gs1 = EventGroupStart[Gi];
		gs2 = EventGroupStart[Gi+1];
		ge0 = gs1-1;
		ge1 = gs2-1;
		
		/******* 计算反射损耗 *******/
		fMaxValue(Ai, FinalEvent[gs1], FinalEventEnd[gs1], &Am, &i);
        A0 = b[ge0] - AC[ge0] * i;   // 用直线拟合出来的事件左值
		RL[gs1] = -(bsc + 2*(Am - A0));    // 反射损耗赋予事件组里的第一个事件
		
		// 如果事件组里的事件多于1个，则最后一个事件也可以拥有反射损耗
		if(gs1 < ge1)
		{
		    fMaxValue(Ai, FinalEvent[ge1], FinalEventEnd[ge1], &Am, &i);
    	    A0 = b[ge1] - AC[ge1] * i;   // 用直线拟合出来的事件左值
    		RL[ge1] = -(bsc + 2*(Am - A0));    // 反射损耗赋予事件组里的第一个事件
		}

		/******* 计算插入损耗 *******/
		Lv = b[ge0] - AC[ge0] * FinalEvent[gs1];   // 用直线拟合出来的事件左值
	    Rv = b[ge1] - AC[ge1] * FinalEvent[gs1];   // 用直线拟合出来的事件右值，和左值在同一个位置
        insert_loss = Lv - Rv;
        IL[gs1]  = insert_loss;             // 插入损耗赋予事件组里的第一个事件
    }
    return insert_loss;
}

/*
 **************************************************************************************************
 *  函数  名： CalculateFSL
 *  函数描述： 根据事件组来计算光纤段的损耗
 *  入口参数： EventTemp : 事件点信息
 *             AC        : 光纤段的衰减系数
 *             EGS       : 事件组的起始事件序号及事件组的个数
 *  返回参数： FSL       : 光纤段损耗
 *             TotalLoss : 光纤段引起的总损耗
 *  日期版本： 2013-1-18 9:25:22  v1.0
 **************************************************************************************************
*/
float CalculateFSL(const int FinalEvent[], const float AC[], \
                   const EventGroupStart_t *EGS, float FSL[])
{
	int	i, gs0, gs1;
	const int	*EventGroupStart;
	float	TotalLoss = 0;

    EventGroupStart = EGS->EventGroupStart;         // 事件组起点
    /******* 计算各个光纤段的损耗 *******/
    for(i = 1; i < EGS->EventGroupNum; i++)
    {
        gs1 = EventGroupStart[i];
        gs0 = EventGroupStart[i-1];
        FSL[gs1-1] = AC[gs1-1] * (FinalEvent[gs1]-FinalEvent[gs0]);
        TotalLoss += FSL[gs1-1];
    }
    return TotalLoss;
}

/*
 **************************************************************************************************
 *  函数  名： CalculateEventPointTL
 *  函数描述： 根据事件组来计算事件点的累计损耗及光纤段的损耗
 *  入口参数： EventTemp : 事件点信息
 *             AC        : 光纤段的衰减系数
 *             IL        : 插入损耗
 *             EGS       : 事件组的起始事件序号及事件组的个数
 *  返回参数： FSL       : 光纤段损耗
 *             TL        : 累计损耗
 *             TotalLoss : 光纤链的总累计损耗
 *  日期版本： 2013-01-11  11:44:33  v1.0
 **************************************************************************************************
*/
float CalculateEventPointTL(const int FinalEvent[], const float AC[], const float IL[], \
                            const EventGroupStart_t *EGS, float FSL[], float TL[])
{
	int	    i, gs, egn;         // 事件组起点
	const int	*EventGroupStart = EGS->EventGroupStart;         // 事件组起点
	float	TotalLoss;

    /******* 计算各个光纤段的损耗 *******/
    CalculateFSL(FinalEvent, AC, EGS, FSL);
    
    /******* 计算各个事件点的累计损耗 *******/
	TotalLoss = 0;
	TL[0]     = 0;//RSVD_FLOAT;
    egn = EGS->EventGroupNum;
    for(i = 1; i < egn; i++)
    {
        gs = EventGroupStart[i];
        TotalLoss += FSL[gs-1];
        
    #if 1    // 如果该事件点存在插入损耗，则计入累计损耗
        if(i < egn-1 && IL[gs] != RSVD_FLOAT)    TotalLoss += IL[gs];
    	TL[gs] = TotalLoss;
    #else    // 即使该事件点存在插入损耗，并不计入累计损耗，而是计算下一个事件点的累计损耗
        TL[gs] = TotalLoss;
        if(i < egn-1 && IL[gs] != RSVD_FLOAT)    TotalLoss += IL[gs];
    #endif
    }

    return TotalLoss;
}

/*
 **************************************************************************************************
 *  函数  名： NormalizeAC_RL
 *  函数描述： 规范化回波损耗和衰减系数
 *  入口参数： StateCtrl    : 状态变量
 *             EventNum : 事件点数
 *  返回参数： AC       : 衰减系数
 *             RL       : 回波损耗
 *  日期版本： 2013-01-18  10:16:50  v1.0
 **************************************************************************************************
*/
static float norm_ac(float ppm, float AC)
{
    return (AC == RSVD_FLOAT) ? RSVD_FLOAT : (AC * ppm * 1000);
}

static float norm_rl(float RL, int evt)
{
    if(evt != EVENT_TYPE_REFLECT)
    {
        RL = RSVD_FLOAT;
    }
    return RL;
}

void NormalizeAC_RL(float ppm, float AC[], float RL[], int EventType[], int EventNum)
{
    int i;
    for(i = 0; i < EventNum; i++)
    {
        AC[i] = norm_ac(ppm, AC[i]);
        RL[i] = norm_rl(RL[i], EventType[i]);
    }
}

/*
 **************************************************************************************************
 *  函数  名： InitEventGroupStart
 *  函数描述： 根据衰减系数来计算事件组的起始事件索引
 *             如果事件组下标为iG
 *             则组成该事件组的第一个事件的下标为EGS.EventGroupStart[iG]
 *             最后一个事件的下标为EGS.EventGroupStart[iG+1]-1
 *             如果两者相同，则表明事件组只有一个事件
 *  入口参数： AttenCoef     : 光纤段的衰减系数
 *             EventNum      : 事件点总数
 *  返回参数： EGS           : 事件组的起始事件序号及事件组的个数
 *             EventGroupNum : 事件组的个数
 *  日期版本： 2013-01-10  17:05:30  v1.0
 **************************************************************************************************
*/
int InitEventGroupStart(const float AttenCoef[], EventGroupStart_t *EGS, int EventNum)
{
    int i, EventGroupNum = 0;
    
    EGS->EventGroupStart[EventGroupNum++] = 0;
    for(i = 1; i < EventNum; i++)
    {
        if(AttenCoef[i-1] != RSVD_FLOAT)    EGS->EventGroupStart[EventGroupNum++] = i;
    }
    EGS->EventGroupNum = EventGroupNum;
    return EventGroupNum;
}

void get_fiber_link_info(float total_len, float active_len, float TotalLoss, FiberLinkInfo_t *FiberLink)
{
    FiberLink->FiberLen = total_len;
    FiberLink->FiberLoss = (TotalLoss == 0) ? RSVD_FLOAT : TotalLoss;

    if(TotalLoss == RSVD_FLOAT)     FiberLink->FiberAttenCoef  = RSVD_FLOAT;
    else
    {
        if(active_len > 0)      FiberLink->FiberAttenCoef = TotalLoss/active_len * 1000;
        else                    FiberLink->FiberAttenCoef = RSVD_FLOAT;
    }
}

/*
 ********************************************************************************
 *  函数名称 ： lsaFitOTDRData  lsaFitAB
 *  函数描述 ： 使用最小二乘法将OTDR曲线的线段拟合成直线，保留事件点和噪声部分
 *              计算AB标杆区间的LSA损耗和衰减系数
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2016-11-04 09:09:47
 ********************************************************************************
*/
void lsaFitOTDRData(const OtdrTestResult_t *result, float *LinearOut)
{
    int i, ei, st, et;
    float k, b, mpp;

    if((result == NULL) || (LinearOut == NULL))             return;
    if((result->valid != 3) || (result->EventNum == 0))     return;

    mpp = LIGHT_SPEED/(2*result->tp.n) / result->tp.SampleRate_Hz;

    // copy start Event
    for(i  = 0; i <= result->ep[0].EventEnd; i++){
        LinearOut[i] = result->Ai[i];
    }

    // copy Fiber and Event
    for(ei = 1; ei < result->EventNum; ei++){
        // get fiber range and LSA get attencoef
        st = result->ep[ei-1].EventEnd + 1;
        et = result->ep[ei].EventStart;
        LeastSquareMethod(result->Ai, st, et, &k, &b);
        k = -result->fs[ei-1].FiberSectionAttenCoef / 1000 / mpp;

        // fit fiber
        for(i = st; i <= et; i++){
            LinearOut[i] = k*i + b;
        }
        // copy Event
        for(i = et; i <= result->ep[ei].EventEnd; i++){
            LinearOut[i] = result->Ai[i];
        }
    }

    // copy from EndEvent to curve end
    for(i = result->ep[result->EventNum-1].EventEnd; i < result->tp.DataNum; i++){
        LinearOut[i] = result->Ai[i];
    }   
}

/*
 ********************************************************************************
 *  函数名称 ： getABResult
 *  函数描述 ： 计算两根标杆的信息
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-05-09 11:38:09
 ********************************************************************************
*/
int getABResult(const OtdrTestResult_t *result, int Apos, int Bpos, \
        float *distance, float *loss2PT, float *coef2PT, float *lossLSA, float *coefLSA)
{
    extern int InitEventGroupStart(const float AttenCoef[], EventGroupStart_t *EGS, int EventNum);
    int i, j, ei, st, et, gs, ge;
    int eventsAB[MAX_EVENT_NUM], en, e1, e2;
	EventGroupStart_t   EGS;
    float k, b, d, ppm, *Ai, A1, A2, AC[MAX_EVENT_NUM];

    if((result == NULL) || (result->valid < 2)){
        *distance = 0.0;
        *loss2PT = RSVD_FLOAT;
        *coef2PT = RSVD_FLOAT;
        *lossLSA = RSVD_FLOAT;
        *coefLSA = RSVD_FLOAT;
        return 1;     // must have Ai, and Event is option
    }

    ppm = 2*result->tp.n * result->tp.SampleRate_Hz / LIGHT_SPEED;

    st = MIN(Apos, Bpos);
    et = MAX(Apos, Bpos);
    d = (et - st) / ppm;
    *distance = d;

    if(st == et){
        *loss2PT = RSVD_FLOAT;
        *coef2PT = RSVD_FLOAT;
        *lossLSA = RSVD_FLOAT;
        *coefLSA = RSVD_FLOAT;
        return 2;
    }

    // calculate 2pt result
    b = fabs(result->Ai[st] - result->Ai[et]);
    k = 1000*b/d;
    *loss2PT = b;
    *coef2PT = k;

    // calculate lsa result, but fit the OTDR curve first
    if(result->valid > 2){
        // 重构事件组
        for(i = 0; i < result->FiberNum; i++){
            AC[i] = result->fs[i].FiberSectionAttenCoef;
        }
        InitEventGroupStart(AC, &EGS, result->EventNum);
    }
    else{
        EGS.EventGroupNum = 0;
    }

    // 判断AB之间是否存在事件组，即它们是否处于同一个光纤段中
    en = 0;
    for(ei = 0; ei < EGS.EventGroupNum; ei++){
        gs = EGS.EventGroupStart[ei];
        if(ei == EGS.EventGroupNum-1)   ge = result->EventNum-1;
        else                            ge = EGS.EventGroupStart[ei+1]-1;
        e1 = result->ep[gs].EventStart;
        e2 = result->ep[ge].EventEnd;
        if((e1 >= st) && (e1 <= et))    eventsAB[en++] = ei;
        else{
            if((e2 >= st) && (e2 <= et))    eventsAB[en++] = ei;
        }
    }

    if(en == 0)  Ai = result->Ai;
    else{
        Ai = (float*)malloc(result->tp.DataNum*sizeof(float));

        // copy curve from result to Ai
        for(i = st; i <= et; i++){
            Ai[i] = result->Ai[i];
        }

        // process events between A and B
        for(j = 0; j < en; j++){
            ei = eventsAB[j];
            gs = EGS.EventGroupStart[ei];
            if(ei == EGS.EventGroupNum-1)   ge = result->EventNum-1;
            else                            ge = EGS.EventGroupStart[ei+1]-1;

            e1 = result->ep[gs].EventStart;
            e2 = result->ep[ge].EventEnd;
            A1 = result->Ai[e1];
            A2 = result->Ai[e2];
            k = (A1 - A2) / (e1 - e2);
            b = A1 - k*e1;

            for(i = e1; i <= e2; i++){
                if((i >= st) && (i <= et)){
                    Ai[i] = k*i + b;
                }
            }
        }
    }

    // LSA
    LeastSquareMethod(Ai, st, et, &k, &b);
    *coefLSA = -k * ppm * 1000;
    *lossLSA = -k * (et - st);
    
    if(en)  free(Ai);
    return 0;
}

/*
 ********************************************************************************
 *  函数名称 ： getTotalLoss
 *  函数描述 ： 计算各个位置上的累计损耗
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-05-09 11:37:36
 ********************************************************************************
*/
void getTotalLoss(const OtdrTestResult_t *result, const int pos[], float loss[], int n)
{
    extern int ThreeArraySort(int *a1, int *a2, int *a3, int n);
    extern int InitEventGroupStart(const float AttenCoef[], EventGroupStart_t *EGS, int EventNum);

    int i, j, ei, st, gs1, gs2;
    int s1, s2;
	EventGroupStart_t   EGS;
    float mpp, AC[MAX_EVENT_NUM];

    if((result == NULL) || (result->valid < 3)){
        for(i = 0; i < n; i++)  loss[i] = RSVD_FLOAT;
        return;     // must have Ai, and Event is option
    }

    mpp = LIGHT_SPEED / (2*result->tp.n*result->tp.SampleRate_Hz);

    // 重构事件组
    for(i = 0; i < result->FiberNum; i++){
        AC[i] = result->fs[i].FiberSectionAttenCoef;
    }
    InitEventGroupStart(AC, &EGS, result->EventNum);

    // 对于每个点，其累计损耗等于最接近它的事件组的累计损耗加上该光纤段引起的衰减
    for(i = 0; i < n; i++){
        st = pos[i];

        // 寻找该位置超过的第一个事件组的下标
        j = EGS.EventGroupNum-1;
        for(ei = 0; ei < EGS.EventGroupNum-1; ei++){
            gs1 = EGS.EventGroupStart[ei];
            gs2 = EGS.EventGroupStart[ei+1];

            s1 = result->ep[gs1].EventStart;
            s2 = result->ep[gs2].EventStart;
            if((st >= s1) && (st < s2)){
                j = ei;   
                break;
            }
        }

        if(j == EGS.EventGroupNum-1)    loss[i] = result->FiberLoss;
        else{
            gs1 = EGS.EventGroupStart[j];
            gs2 = EGS.EventGroupStart[j+1]-1;

            loss[i] = result->ep[gs1].EventTotalloss + AC[gs2] * (st - result->ep[gs1].EventStart) * mpp / 1000;
        }
    }
}

/*
 ********************************************************************************
 *  函数名称 ： index2Length  length2Index  getDisplayPoints
 *  函数描述 ： 
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2016-11-25 15:01:35
 ********************************************************************************
*/
float getDataSpace(const OtdrTestResult_t *tr)
{
    int f = tr->tp.SampleRate_Hz;
    float refraction = tr->tp.n;

    return LIGHT_SPEED / (2*refraction*f);
}

float index2Length(unsigned int index, float data_space)
{
    return index * data_space;
}

int length2Index(float len, float data_space)
{
    return (int)(len / data_space);
}

int getDisplayPoints(int MeasureLength_m, float data_space)
{
    int n = length2Index((float)MeasureLength_m, data_space);

    // align to even
    //if(n & 1)   n++;
    return n;
}

// 新版接口函数
int getPulseWidth_M2(const OtdrTestParam_t *tp)
{
    int M;
    M = (int)(tp->PulseWidth_ns * (tp->SampleRate_Hz / 1000) / 1e6);
    M = MAX(M, 2);

    return M;
}

/*
 ********************************************************************************
 *  函数名称 ： OtdrBuildEventList
 *  函数描述 ： 根据从SOR文件读取的事件列表来构建缺失的参数，
 *              包含事件点的累计损耗和光纤段参数
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-04-18 10:31:05
 ********************************************************************************
*/
int OtdrBuildEventList(OtdrTestResult_t *tr)
{
    float mpp, ppm, temp, TotalLoss;
    float AttenCoef[MAX_EVENT_NUM], IL[MAX_EVENT_NUM], TL[MAX_EVENT_NUM], FSL[MAX_EVENT_NUM];
    int i, M, fi, EventNum, SampleRate_Hz, EventGroupNum, FinalEvent[MAX_EVENT_NUM]; 
	EventGroupStart_t   EGS;

    assert(tr != NULL);

    SampleRate_Hz = tr->tp.SampleRate_Hz;
    ppm = 2*tr->tp.n * SampleRate_Hz / LIGHT_SPEED;
    mpp = 1/ppm;
    M = (int)(tr->tp.PulseWidth_ns * SampleRate_Hz / 1000 / 1e6);

    EventNum = tr->EventNum;

    // 初始化数组
    for(i = 0; i < MAX_EVENT_NUM; i++){
        AttenCoef[i] = RSVD_FLOAT;
        IL[i] = RSVD_FLOAT;
        TL[i] = RSVD_FLOAT;
        FSL[i] = RSVD_FLOAT;
    }

    // 重构段衰减系数列表
    for(i = 0; i < EventNum; i++){
        FinalEvent[i] = tr->ep[i].EventStart;
        if(FinalEvent[i] + M > tr->ep[i].EventEnd)   tr->ep[i].EventEnd = FinalEvent[i] + M;

        IL[i] = tr->ep[i].EventInsertloss;
    }

    for(i = 0; i < EventNum-1; i++){
        temp = tr->fs[i].FiberSectionAttenCoef;
        if(fabs(temp) > 0.01 && temp != RSVD_FLOAT)     temp = temp * mpp / 1000;
        else                                            temp = RSVD_FLOAT;

        AttenCoef[i] = temp;
    }

    // 根据段衰减系数重构事件组
    EventGroupNum = InitEventGroupStart(AttenCoef, &EGS, EventNum);

    // 计算各个事件点的累计损耗及光纤段的损耗
    TotalLoss = CalculateEventPointTL(FinalEvent, AttenCoef, IL, &EGS, FSL, TL);
    
/**************************** 已确定各个事件点的累计损耗，填充数据结构 ***********************************/
    // fill event first
    for(i = 0; i < EventNum; i++)
    {
        /*************************** event point **********************************/
        tr->ep[i].EventTotalloss  = TL[i];
    }

    // then fill fiber
    fi = 0;
    for(i = 1; i < EventNum; i++)
    {
/*************************** fiber section **********************************/
        tr->fs[fi].FiberSectionLen	     = FinalEvent[i] - FinalEvent[i-1];
        tr->fs[fi].FiberSectionLoss      = FSL[i-1];
        fi++;
    }
    tr->FiberNum = fi;

/*************************** 更新前面的全局链损耗和链平均衰减系数 ********************************/
    {
        int gs1;
        float total_len, active_len;
        // 计算光纤的链长
        if(EventNum > 1)    total_len = mpp * FinalEvent[EventNum-1];
        else                total_len = 0;

        gs1 = EGS.EventGroupStart[EventGroupNum-1];
        active_len = mpp * FinalEvent[gs1];
        get_fiber_link_info(total_len, active_len, TotalLoss, (FiberLinkInfo_t*)&tr->FiberLen);
    }

    PrintEventList(tr);
    return 0;
}


/*
 ********************************************************************************
 *  函数名称 ： 
 *  函数描述 ： 
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-05-09 14:15:13
 ********************************************************************************
*/
int checkForEventEdit(const OtdrTestResult_t *tr, int pos, int *can_be_add, int *selected_event)
{
    int i, M, add, selected_ei;
    assert(tr != NULL);

    M = getPulseWidth_M2(&tr->tp);
    add = 0;
    selected_ei = -1;

    // check if selected first event
    if(pos >= tr->ep[0].EventStart && pos <= tr->ep[0].EventEnd+M)  selected_ei = 0;

    // check if it can be added here
    for(i = 1; i < tr->EventNum; i++){
        if(pos > tr->ep[i-1].EventEnd+M && pos < tr->ep[i].EventStart-M)  add = 1;
        else if(pos >= tr->ep[i].EventStart-M && pos <= tr->ep[i].EventEnd+M)  selected_ei = i;
    }
    // end event until noise
    if(pos > tr->ep[tr->EventNum-1].EventEnd + M && pos < tr->tp.DataNum-M)  add = 1;

    if(tr->EventNum == MAX_EVENT_NUM)   add = 0;

    if(can_be_add != NULL)      *can_be_add = add;
    if(selected_event != NULL)  *selected_event = selected_ei;
    
    return 0;
}

int algo_event_type_2_sor_event_type(int algo_event_type, int is_last_event)
{
    int ec1, ec2;
    if(algo_event_type == EVENT_TYPE_NONREFLECT)        ec1 = EC1_NONREFLECT;
    else if(algo_event_type == EVENT_TYPE_REFLECT)      ec1 = EC1_REFLECT;
    else if(algo_event_type == EVENT_TYPE_PROBABLE)     ec1 = EC1_NONREFLECT;
    else                                                ec1 = EC1_SATURATE;

    if(is_last_event){
        if(algo_event_type == EVENT_TYPE_PROBABLE)      ec2 = EC2_O;
        else                                            ec2 = EC2_E;
    }
    else                                                ec2 = EC2_F;

    return (ec2 << 8) | ec1;
}

int sor_event_type_2_algo_event_type(int sor_event_type)
{
    int ec1, ec2, type;

    ec1 = sor_event_type & 0xff;
    ec2 = (sor_event_type >> 8) & 0xff;

    if(ec2 == EC2_O)                type = EVENT_TYPE_PROBABLE;
    else if(ec1 == EC1_NONREFLECT)  type = EVENT_TYPE_NONREFLECT;
    else                            type = EVENT_TYPE_REFLECT;

    return type;
}

int EventParamFromEvent_t(const OtdrTestParam_t *tp, \
                          const float Ai[], \
                          Event_t *EventTemp, \
                          EventPoint_t ep[], \
                          FiberSection_t fs[], \
                          FiberLinkInfo_t *FiberLink)
{
    int	i, gs1, ei, uo_ei, uo;
    int	EventNum;

    int	*FinalEvent, *FinalEventEnd, *EventType, *EventGroupStart, EventGroupNum;
    float	Distance_m, TotalLoss;
    float	mpp, ppm, BackwardScatterCoeff;
    float	*DataTemp, *EventReturnLoss, *EventInsertLoss, *AttenCoef, *EventTotalLoss, *FiberSectionLoss, *b0;
    EventGroupStart_t   EGS;

    FinalEvent     = EventTemp->FinalEvent;        // 事件起点
    FinalEventEnd  = EventTemp->FinalEventEnd;     // 事件末点
    EventType       = EventTemp->EventType;         // 事件类型
    EventNum        = EventTemp->FinalEventNum;
    EventGroupStart = EGS.EventGroupStart;          // 事件组起点

    DataTemp = (float*)malloc(MAX_EVENT_NUM * 10 * sizeof(float));
    EventReturnLoss = (float*)(DataTemp);
    EventInsertLoss  = (float*)(EventReturnLoss + MAX_EVENT_NUM);
    AttenCoef        = (float*)(EventInsertLoss  + MAX_EVENT_NUM);
    EventTotalLoss   = (float*)(AttenCoef        + MAX_EVENT_NUM);
    b0               = (float*)(EventTotalLoss   + MAX_EVENT_NUM);
    FiberSectionLoss = (float*)(b0               + MAX_EVENT_NUM);

    for(i = 0; i < MAX_EVENT_NUM; i++)
    {
        EventReturnLoss[i] = RSVD_FLOAT;
        EventInsertLoss[i]  = RSVD_FLOAT;
        AttenCoef[i]        = RSVD_FLOAT;
        EventTotalLoss[i]   = RSVD_FLOAT;
        b0[i]               = RSVD_FLOAT;
        FiberSectionLoss[i] = RSVD_FLOAT;
    }

    // 获取实际使用的采样率和折射率，并计算系数
    mpp = LIGHT_SPEED / (2*tp->n*tp->SampleRate_Hz);
    ppm = 1/mpp;

    // 后向散射系数
    GetLaserParam(tp->Lambda_nm, NULL, &BackwardScatterCoeff);
    BackwardScatterCoeff += 10 * log10(tp->PulseWidth_ns);      // 2012-3-22 17:37:44

    /******* 根据相邻事件点的距离来判断哪些事件可以计算衰减系数 *******/
    EventNum = EventTemp->FinalEventNum;
    for(i = 0; (i < EventNum) && (i < MAX_EVENT_NUM); i++)  // 2011-5-7 11:19:14
    {
        AttenCoef[i] = CalculateFiberSectionAttenCoef(tp, Ai, FinalEvent, FinalEventEnd, EventNum, i, &b0[i]);
    }

    // 寻找事件点里的组。 数组EventGroupStart保存每个事件组的起始事件的序号
    // 如果某个事件是独立事件而不是事件组，则数组在这里取值连续，否则不连续
    EventGroupNum = InitEventGroupStart(AttenCoef, &EGS, EventNum);

    /******* 根据事件组来计算其参数 *******/
    EventNum = EventTemp->FinalEventNum;
    for(i = 0; i < EventGroupNum; i++)  // 2012-9-24 15:08:39
    {
        gs1 = EventGroupStart[i];
        CalculateEventPoint_IL_RL(Ai, FinalEvent, FinalEventEnd, AttenCoef, b0, &EGS, 
                i, BackwardScatterCoeff, EventInsertLoss, EventReturnLoss);
    }

    /******* 计算各个事件点的累计损耗及光纤段的损耗 *******/
    TotalLoss = CalculateEventPointTL(FinalEvent, AttenCoef, EventInsertLoss, &EGS, FiberSectionLoss, EventTotalLoss);

    /******* 规范化回波损耗和衰减系数 *******/
    NormalizeAC_RL(ppm, AttenCoef, EventReturnLoss, EventType, EventNum);

    /**************************** 已确定各个事件点的累计损耗，填充数据结构 ***********************************/
    // fill event first
    uo_ei = 0;
    uo = ppm*tp->rsvd1/1000.0;
    for(i = 0; i < EventNum; i++)
    {
        if(FinalEvent[i] >= uo){
            uo_ei = i;
            break;
        }
    }

    // 覆盖uo之前的事件
    for(i = uo_ei, ei = 0; i < EventNum; i++, ei++)
    {
        ep[ei].EventStart      = FinalEvent[i];
        ep[ei].EventEnd        = FinalEventEnd[i];
        ep[ei].EventType       = algo_event_type_2_sor_event_type(EventType[i], (i==EventNum-1));
        ep[ei].EventReturnloss = EventReturnLoss[i];
        ep[ei].EventInsertloss = EventInsertLoss[i];
        ep[ei].EventTotalloss  = EventTotalLoss[i];

        if(i < EventNum-1){
            fs[ei].FiberSectionLen = FinalEvent[i+1] - FinalEvent[i];
        }
        fs[ei].FiberSectionLoss = FiberSectionLoss[i];
        fs[ei].FiberSectionAttenCoef = AttenCoef[i];
    }

    /*************************** 更新前面的全局链损耗和链平均衰减系数 ********************************/
    FiberLink->FiberLoss = (TotalLoss == 0) ? RSVD_FLOAT : TotalLoss;
    if(TotalLoss == RSVD_FLOAT)     FiberLink->FiberAttenCoef  = RSVD_FLOAT;
    else
    {
        // 计算光纤的链长
        if(EventNum > 1)    Distance_m = mpp * FinalEvent[EventNum-1];
        else                Distance_m = 0;
        FiberLink->FiberLen = Distance_m;

        gs1 = EventGroupStart[EventGroupNum-1];
        Distance_m = mpp * FinalEvent[gs1];
        if(Distance_m > 0)      FiberLink->FiberAttenCoef = TotalLoss/Distance_m * 1000;
        else                    FiberLink->FiberAttenCoef = RSVD_FLOAT;
    }

    free(DataTemp);
    return ei;
}

int getOtdrNewEventParam(const OtdrTestResult_t *tr, float pos_m, EventPoint_t *ev)
{
    int i, j, M, pos, can_be_add;
    int et, eventend, evt, evt_ec1, evt_ec2, peakpos, this_ei;
    int *FinalEvent, *FinalEventEnd, *EventType, FinalEventNum;
    float *Ai, peak;
    Event_t EventTemp;
    EventPoint_t ep[MAX_EVENT_NUM];
    FiberSection_t fs[MAX_EVENT_NUM];
    FiberLinkInfo_t FiberLink;

    assert(tr != NULL);
    pos = pos_m / getDataSpace(tr);
    checkForEventEdit(tr, pos, &can_be_add, NULL);
    if(can_be_add != 1) return E_ADDEVENT;

    Ai = tr->Ai;
    M = getPulseWidth_M2(&tr->tp);

    et = tr->tp.DataNum - 2*M;
    this_ei = tr->EventNum;
    for(i = 1; i < tr->EventNum; i++){
        if(pos < tr->ep[i].EventStart){
            et = tr->ep[i].EventStart - M;
            this_ei = i;
            break;
        }
    }
    // 添加结束事件还是添加中间事件，决定好其事件类型
    if(this_ei == tr->EventNum) evt_ec2 = EC2_D;
    else                        evt_ec2 = EC2_A;

    // find EventEnd
    // new event store in last element of ep[]
    fMaxValue(Ai, pos, pos+2*M, &peak, &peakpos);
    eventend = peakpos+M;
    for(i = eventend; i < et; i++){
        if(Ai[i] > Ai[i-M]){
            eventend = i;
            break;
        }
    }
    // event type
    if(peak - Ai[pos] > 0.5 && peak > 5)    {evt = EVENT_TYPE_REFLECT   , evt_ec1 = EC1_REFLECT   ;}
    else                                    {evt = EVENT_TYPE_NONREFLECT, evt_ec1 = EC1_NONREFLECT;}

    // build eventtemp
	FinalEvent = EventTemp.FinalEvent;
	FinalEventEnd = EventTemp.FinalEventEnd;
	EventType = EventTemp.EventType;
	FinalEventNum = tr->EventNum;
    for(i = 0, j = 0; i < this_ei; i++, j++){
        FinalEvent[j] = tr->ep[i].EventStart;
        FinalEventEnd[j] = tr->ep[i].EventEnd;
        EventType[j] = sor_event_type_2_algo_event_type(tr->ep[i].EventType);
    }
    // new event
    FinalEvent[j] = pos;
    FinalEventEnd[j] = eventend;
    EventType[j] = evt;
    j++;
    for(; i < tr->EventNum; i++, j++){
        FinalEvent[j] = tr->ep[i].EventStart;
        FinalEventEnd[j] = tr->ep[i].EventEnd;
        EventType[j] = sor_event_type_2_algo_event_type(tr->ep[i].EventType);
    }
    FinalEventNum++;
    EventTemp.FinalEventNum = FinalEventNum;

    EventParamFromEvent_t(&tr->tp, Ai, &EventTemp, ep, fs, &FiberLink);
#if 0
    memcpy(tr->ep, ep, sizeof(ep));
    memcpy(tr->fs, fs, sizeof(fs));
    memcpy(&tr->FiberLen, &FiberLink, sizeof(FiberLink));
    tr->EventNum++;
    tr->FiberNum++;
#endif

    // return result
    ev->EventStart      = ep[this_ei].EventStart;
    ev->EventEnd        = ep[this_ei].EventEnd;
    ev->EventType       = (evt_ec2 << 8) | evt_ec1;
    ev->EventReturnloss = ep[this_ei].EventReturnloss;
    ev->EventInsertloss = ep[this_ei].EventInsertloss;
    ev->EventTotalloss  = ep[this_ei].EventTotalloss;

    PrintEventList(tr);
    printf("\n******** NEW EVENT ********\n");
    printf("Event  Position  InsertLoss  ReturnLoss  AttenCoef  TotalLoss\n");
    printf(" %-4d  %-8d  %-10.3f  %-11.3f  %-9.4f  %-9.3f\n", this_ei, ev->EventStart, 
            ev->EventInsertloss, ev->EventReturnloss, 
            fs[this_ei].FiberSectionAttenCoef, ev->EventTotalloss);

    return E_CMD_OK;
}

/*
 ********************************************************************************
 *  函数名称 ： OtdrAddEventPoint
 *  函数描述 ： 
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-06-09 10:17:45
 ********************************************************************************
*/
float TotalLossFromTestResult_t(const OtdrTestResult_t *result, float TL[], int *ActiveLen)
{
	int	    i, en, active_ei;         // 事件组起点
	float	TotalLoss, fsl, il;

    /******* 计算各个事件点的累计损耗 *******/
	TotalLoss = 0;
	TL[0]     = 0;//RSVD_FLOAT;
    en        = result->EventNum;
    for(i = 1; i < en; i++)
    {
        fsl = result->fs[i-1].FiberSectionLoss;
        il = result->ep[i].EventInsertloss;

        if(fsl != RSVD_FLOAT){
            active_ei = i;
            TotalLoss += fsl;
        }
        else                    continue;       // 没有衰减系数，下一个事件点将没有插损，也没有累计损耗
        
        // 如果该事件点存在插入损耗，则计入累计损耗
        if(i < en-1 && il != RSVD_FLOAT)    TotalLoss += il;
    	TL[i] = TotalLoss;
    }

    if(NULL != ActiveLen)   *ActiveLen = result->ep[active_ei].EventStart - result->ep[0].EventStart;
    return TotalLoss;
}

int OtdrAddEventPoint(OtdrTestResult_t *tr, EventPoint_t ev)
{
    int i, j, M, all_len, active_len;
    int evt_ec1, evt_ec2, event_index, fiber_index;
    int FinalEvent[MAX_EVENT_NUM], FinalEventEnd[MAX_EVENT_NUM], FinalEventNum;
    float *Ai, ppm, ac[2], tl, TL[MAX_EVENT_NUM];
    FiberSection_t fs[2];

    assert(tr != NULL);
    checkForEventEdit(tr, ev.EventStart, &i, NULL);
    if(i != 1) return E_ADDEVENT;
    printf("*********************** Adding EventPoint ***********************\n");

    Ai = tr->Ai;
    M = getPulseWidth_M2(&tr->tp);

    for(i = 0; i < tr->EventNum; i++){
        if(ev.EventStart < tr->ep[i].EventStart){
            break;
        }
    }
    event_index = i;    // event_index must be > 0
    fiber_index = event_index - 1;

    // 添加结束事件还是添加中间事件，决定好其事件类型
    evt_ec1 = ev.EventType & 0xff;
    if(event_index == tr->EventNum) evt_ec2 = EC2_D;
    else                        evt_ec2 = EC2_A;
    ev.EventType = (evt_ec2 << 8) | evt_ec1;

    // build eventtemp
	FinalEventNum = tr->EventNum;
    for(i = 0, j = 0; i < event_index; i++, j++){
        FinalEvent[j] = tr->ep[i].EventStart;
        FinalEventEnd[j] = tr->ep[i].EventEnd;
    }
    // new event
    FinalEvent[j] = ev.EventStart;
    FinalEventEnd[j] = ev.EventEnd;
    j++;
    for(; i < tr->EventNum; i++, j++){
        FinalEvent[j] = tr->ep[i].EventStart;
        FinalEventEnd[j] = tr->ep[i].EventEnd;
    }
    FinalEventNum++;

    ac[0] = CalculateFiberSectionAttenCoef(&tr->tp, Ai, FinalEvent, FinalEventEnd, FinalEventNum, event_index-1, NULL);
    ac[1] = CalculateFiberSectionAttenCoef(&tr->tp, Ai, FinalEvent, FinalEventEnd, FinalEventNum, event_index  , NULL);

    ppm = getDataSpace(tr);
    ppm = 1/ppm;
    fs[0].FiberSectionLen = ev.EventStart - tr->ep[event_index-1].EventStart;
    fs[1].FiberSectionLen = tr->ep[event_index].EventStart - ev.EventStart;

    fs[0].FiberSectionAttenCoef = norm_ac(ppm, ac[0]);
    fs[1].FiberSectionAttenCoef = norm_ac(ppm, ac[1]);

    if(ac[0] != RSVD_FLOAT){
        fs[0].FiberSectionLoss = ac[0] * fs[0].FiberSectionLen;
    }
    else    fs[0].FiberSectionLoss = RSVD_FLOAT;
    if(ac[1] != RSVD_FLOAT){
        fs[1].FiberSectionLoss = ac[1] * fs[1].FiberSectionLen;
    }
    else    fs[1].FiberSectionLoss = RSVD_FLOAT;

    // add event to list
    for(i = tr->EventNum; i > event_index; i--){
        memcpy(&tr->ep[i], &tr->ep[i-1], sizeof(tr->ep[0]));
    }
    memcpy(&tr->ep[event_index], &ev, sizeof(ev));
    tr->EventNum = FinalEventNum;
    // add fiber section
    for(i = tr->FiberNum; i > fiber_index; i--){
        memcpy(&tr->fs[i], &tr->fs[i-1], sizeof(tr->fs[0]));
    }
    memcpy(&tr->fs[fiber_index]  , &fs[0], sizeof(fs[0]));
    memcpy(&tr->fs[fiber_index+1], &fs[1], sizeof(fs[1]));
    tr->FiberNum = FinalEventNum-1;

    tl = TotalLossFromTestResult_t(tr, TL, &active_len);
    for(i = 0; i < tr->EventNum; i++){
        tr->ep[i].EventTotalloss = TL[i];
    }

    all_len = tr->ep[tr->EventNum-1].EventStart - tr->ep[0].EventStart;
    get_fiber_link_info(all_len/ppm, active_len/ppm, tl, (FiberLinkInfo_t*)&tr->FiberLen);

    PrintEventList(tr);
    PrintFiberList(tr);
    return E_CMD_OK;
}

/*
 ********************************************************************************
 *  函数名称 ： OtdrModifyEventPoint
 *  函数描述 ： 修改事件
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-06-13 09:31:56
 ********************************************************************************
*/
int OtdrModifyEventPoint(OtdrTestResult_t *tr, int event_index, EventPoint_t ev)
{
    int i, j, M, AL, can_be_add;
    int et, eventend, evt_ec1, evt_ec2, peakpos, this_ei, fiber_index;
    int *FinalEvent, *FinalEventEnd, *EventType, FinalEventNum;
    float *Ai, ppm, ac[2], tl, TL[MAX_EVENT_NUM];
    Event_t EventTemp;
    EventPoint_t ep[MAX_EVENT_NUM];
    FiberSection_t fs[MAX_EVENT_NUM];
    FiberLinkInfo_t FiberLink;

    assert(tr != NULL);
    if(event_index < 0 || event_index >= tr->EventNum)  return E_MODIFY_EVENT;
    printf("*********************** Modifying EventPoint ***********************\n");

    Ai = tr->Ai;
    M = getPulseWidth_M2(&tr->tp);

    // 修改结束事件还是修改中间事件，决定好其事件类型
    evt_ec1 = ev.EventType & 0xff;
    if(event_index == tr->EventNum-1)   evt_ec2 = EC2_D;
    else                                evt_ec2 = EC2_M;
    ev.EventType = (evt_ec2 << 8) | evt_ec1;
#if 0
    // build eventtemp
    FinalEvent = EventTemp.FinalEvent;
    FinalEventEnd = EventTemp.FinalEventEnd;
    EventType = EventTemp.EventType;
	FinalEventNum = tr->EventNum;
    for(i = 0; i < FinalEventNum; i++){
        FinalEvent[i] = tr->ep[i].EventStart;
        FinalEventEnd[i] = tr->ep[i].EventEnd;
        EventType[i] = sor_event_type_2_algo_event_type(tr->ep[i].EventType);
        IL[i] = tr->ep[i].EventInsertloss;
        RL[i] = tr->ep[i].EventReturnloss;
        TL[i] = tr->ep[i].EventTotalloss;
    }

    // 如果事件点的位置发生变化，则重新计算衰减系数
    if(ev.EventStart != FinalEvent[event_index]){
        EventParamFromEvent_t(&tr->tp, Ai, &EventTemp, ep, fs, &FiberLink);

    }

    ac[0] = CalculateFiberSectionAttenCoef(&tr->tp, Ai, FinalEvent, FinalEventEnd, FinalEventNum, this_ei-1, NULL);
    ac[1] = CalculateFiberSectionAttenCoef(&tr->tp, Ai, FinalEvent, FinalEventEnd, FinalEventNum, this_ei  , NULL);

    ppm = getDataSpace(tr);
    ppm = 1/ppm;
    fs[0].FiberSectionLen = ev.EventStart - tr->ep[this_ei-1].EventStart;
    fs[1].FiberSectionLen = tr->ep[this_ei].EventStart - ev.EventStart;

    fs[0].FiberSectionAttenCoef = norm_ac(ppm, ac[0]);
    fs[1].FiberSectionAttenCoef = norm_ac(ppm, ac[1]);

    if(ac[0] != RSVD_FLOAT){
        fs[0].FiberSectionLoss = ac[0] * fs[0].FiberSectionLen;
    }
    else    fs[0].FiberSectionLoss = RSVD_FLOAT;
    if(ac[1] != RSVD_FLOAT){
        fs[1].FiberSectionLoss = ac[1] * fs[1].FiberSectionLen;
    }
    else    fs[1].FiberSectionLoss = RSVD_FLOAT;
#endif
    // add event to list without Eventtotalloss
    ev.EventTotalloss = tr->ep[event_index].EventTotalloss;
    memcpy(&tr->ep[event_index], &ev, sizeof(ev));
    PrintEventList(tr);
    PrintFiberList(tr);
    return E_CMD_OK;
}

/*
 ********************************************************************************
 *  函数名称 ： OtdrDeleteEventPoint
 *  函数描述 ： 删除事件
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-06-14 11:48:43
 ********************************************************************************
*/
int OtdrDeleteEventPoint(OtdrTestResult_t *tr, int event_index)
{
    int i, j;
    int evt_ec1, evt_ec2, fiber_index;
    int *FinalEvent, *FinalEventEnd, *EventType, FinalEventNum;
    float *Ai, ppm, ac[2], tl, TL[MAX_EVENT_NUM];
    Event_t EventTemp;
    EventPoint_t ep[MAX_EVENT_NUM];
    FiberSection_t fs[MAX_EVENT_NUM];
    FiberLinkInfo_t FiberLink;

    assert(tr != NULL);
    if(event_index <= 0 || event_index >= tr->EventNum)  return E_DELETE_EVENT;
    Ai = tr->Ai;

    printf("*********************** Deleting EventPoint ***********************\n");
    // build eventtemp
    FinalEvent = EventTemp.FinalEvent;
    FinalEventEnd = EventTemp.FinalEventEnd;
    EventType = EventTemp.EventType;
	FinalEventNum = tr->EventNum;
    for(i = 0, j = 0; i < FinalEventNum; i++){
        if(i == event_index)    continue;
        FinalEvent[j] = tr->ep[i].EventStart;
        FinalEventEnd[j] = tr->ep[i].EventEnd;
        EventType[j] = sor_event_type_2_algo_event_type(tr->ep[i].EventType);
        j++;
    }
    EventTemp.FinalEventNum = j;

    EventParamFromEvent_t(&tr->tp, Ai, &EventTemp, tr->ep, tr->fs, (FiberLinkInfo_t*)&tr->FiberLen);
    tr->EventNum = EventTemp.FinalEventNum;
    tr->FiberNum = EventTemp.FinalEventNum-1;

    PrintEventList(tr);
    PrintFiberList(tr);
    return E_CMD_OK;
}

/*
 ********************************************************************************
 *  函数名称 ： OtdrEventEdit
 *  函数描述 ： 整合事件编辑的3个函数
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-06-14 11:54:06
 ********************************************************************************
*/
int OtdrEventEdit(char *operation, OtdrTestResult_t *tr, int event_index, EventPoint_t ev)
{
    extern int strcasecmp_free(const char *s1, const char *s2);

    if(!strcasecmp_free(operation, "add")){
        return OtdrAddEventPoint(tr, ev);
    }
    else if(!strcasecmp_free(operation, "modify")){
        return OtdrModifyEventPoint(tr, event_index, ev);
    }
    else if(!strcasecmp_free(operation, "delete")){
        return OtdrDeleteEventPoint(tr, event_index);
    }
    else{
        printf("not support operation!\n");
        return 1;
    }
}

#if 0
/*
 ********************************************************************************
 *  函数名称 ： 
 *  函数描述 ： 
 *  入口参数 ： 
 *  返回参数 ： 
 *  日期版本 ： 2017-05-09 14:13:01
 ********************************************************************************
*/
int moveAB(int direction, int )
int xZoom()
int yZoom()

#endif

#undef _DEVICE_INDEPENDENT_

/*
 **************************************************************************************
 *    End    of    File
 **************************************************************************************
*/
